package com.lp.multi.juc.collection;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @author: lp
 * @create: 2021-06-27 17:13
 * @description: 信号量(抢车位)
 * 3个车位6人抢
 * 信号量维持一组许可证
 * 信号量通常用于限制线程数，而不是访问某些（物理或逻辑）资源,如Pool
 *
 */
public class SemaphoreTest {
    public static void main(String[] args) {
        //3个许可证
        //fair为true，公平锁，先进先出
        Semaphore semaphore = new Semaphore(3,true);
        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                try {
                    //直到获取凭证为止
                    System.out.println(Thread.currentThread().getName()+"尝试获取凭证");
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"获得了凭证");
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    System.out.println(Thread.currentThread().getName()+"释放了凭证");
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }

}

class Pool {
    private static final int MAX_AVAILABLE = 100;
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
    // Not a particularly efficient data structure; just for demo
     protected Object[] items = null;
     // whatever kinds of items being managed
    protected boolean[] used = new boolean[MAX_AVAILABLE];
    public Object getItem() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }
    public void putItem(Object x) {
        if (markAsUnused(x)) {
            available.release();
        }
    }

    protected synchronized Object getNextAvailableItem() {
            for (int i = 0; i < MAX_AVAILABLE; ++i){
                if (!used[i]) {
                    used[i] = true;
                    return items[i];
                }
            }
         // not reached
            return null;
     }
    protected synchronized boolean markAsUnused(Object item) {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (item == items[i]) {
                if (used[i]) {
                    used[i] = false;
                    return true;
                } else{
                    return false;
                }
            }
            }
        return false;
    }
 }
